package com.pvdnc.riru.system_server;

import android.content.pm.ApplicationInfo;
import android.os.IBinder;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

public class PMSUtils {
    private static final String TAG=PMSUtils.class.getSimpleName();

    private static final AtomicReference<PMSUtils> sInstance=new AtomicReference<>();

    public static void systemReady(IBinder service){
        sInstance.set(new PMSUtils(service));
    }

    public static PMSUtils get(){
        return sInstance.get();
    }

    private PMSUtils(IBinder service){
        mService=service;
    }

    private final IBinder mService;

    public Class<?> getPMSClass() throws Exception {
        Class<?> pmsClass=mService.getClass();
        Log.d(TAG,"pmsClass:"+pmsClass);
        return pmsClass;
    }

    public Map<String,Object> getPackageMap() throws Exception {
        Class<?> pmsClass=getPMSClass();
        Field mapField= pmsClass.getDeclaredField("mPackages");
        mapField.setAccessible(true);
        Map<String,Object> packageMap= (Map<String, Object>) mapField.get(mService);
        Objects.requireNonNull(packageMap);
        return packageMap;
    }

    public ApplicationInfo getApplicationInfo(String packageName){
        try{
            Map<String,Object> packageMap=getPackageMap();
            Object parserPkg= packageMap.get(packageName);
            if(parserPkg==null) {
                Log.e(TAG,"package:"+packageName+" may not exist");
                return null;
            }
            ApplicationInfo appInfo= getApplicationInfo(parserPkg);
            Log.d(TAG,"pkg:"+packageName+" app info:\n\t"+appInfo);
            return appInfo;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    public ApplicationInfo getApplicationInfo(Object parserPkg) throws Exception {
        Class<?> parserPkgClass=parserPkg.getClass();
        Field appInfoField= parserPkgClass.getDeclaredField("applicationInfo");
        appInfoField.setAccessible(true);
        return (ApplicationInfo) appInfoField.get(parserPkg);
    }

    private final Map<String,ApplicationInfo> mPkgNameAppInfoMap=new ConcurrentHashMap<>();

    public int getUidByPackageName(String pkgName) throws IllegalArgumentException{
        ApplicationInfo info= mPkgNameAppInfoMap.get(pkgName);
        if(info!=null)
            return info.uid;
        //缓存查询结果
        info= getApplicationInfo(pkgName);
        if(info==null)
            throw new IllegalArgumentException("pkgName:"+pkgName+" may not exist");
        mPkgNameAppInfoMap.put(pkgName,info);
        int uid=info.uid;
        Log.d(TAG,"pkgName:"+pkgName+" -> uid:"+uid);
        return uid;
    }

    public String getPackageNameForUid(int uid){
        try {
            Class<?> pmsClass=getPMSClass();
            //public String getNameForUid(int uid)
            Method method=pmsClass.getDeclaredMethod("getNameForUid",
                    int.class);
            method.setAccessible(true);
            String pkgName= (String) method.invoke(mService,uid);
            Log.d(TAG,"uid:"+uid+" -> pkg:"+pkgName);
            return pkgName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
